package com.obixlabs.security.credentialsstore.server.serviceimpl;

import javax.jws.WebService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.obixlabs.security.credentialsstore.exception.EntryAlreadyExistsException;
import com.obixlabs.security.credentialsstore.exception.EntryNotFoundException;
import com.obixlabs.security.credentialsstore.model.BaseUser;
import com.obixlabs.security.credentialsstore.model.User;
import com.obixlabs.security.credentialsstore.server.dao.UserDAO;
import com.obixlabs.security.credentialsstore.services.SecurityServiceConstants;
import com.obixlabs.security.credentialsstore.services.UserManagementService;

@WebService (	name=UserManagementService.SERVICE_NAME, 
				targetNamespace=SecurityServiceConstants.SECURITY_SERVICES_TARGET_NAMESPACE)
public class UserManagementServiceDefaultImpl 	extends ConcurrentServiceBase 
												implements UserManagementService
{
	private static final Logger logger = 
		LoggerFactory.getLogger(UserManagementServiceDefaultImpl.class);
	
	private UserDAO userDAO;
	
	public void setUserDAO(UserDAO userDAO){this.userDAO = userDAO;}
	public UserDAO getUserDAO(){return userDAO;}
		
	public String getServiceName(){return UserManagementService.SERVICE_NAME;}
	
	@Override
	public User authenticateHumanUser(String username, String password)
	{
		User result;
		lockForRead();
		try
		{
			if (logger.isDebugEnabled())
				logger.debug("Attempting to authenticate human user: " + username);
			result = userDAO.findHumanUserByIdAndPassword(username, password);
		} 
		finally { unlockAfterRead(); }
		return result;
	}

	@Override
	public BaseUser authenticateUser(String username, String password)
	{
		BaseUser result;
		lockForRead();
		try
		{		
			if (logger.isDebugEnabled())
				logger.debug("Attempting to authenticate user: " + username);
			result = userDAO.findByUserIdAndPassword(username, password);
		} 
		finally { unlockAfterRead(); }
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public <T extends BaseUser> T refreshUserDetails(T user)
	{
		lockForRead();
		try
		{		
			if (logger.isDebugEnabled())
				logger.debug("Attempting to find user: " + user.getUserId());
			
			if (user instanceof User)
				return (T) userDAO.findHumanUserByUserId(user.getUserId());
			else return (T) userDAO.findByUserId(user.getUserId());
		} 
		finally { unlockAfterRead(); }		
	}
	
	@Override
	public BaseUser findByEmailAddress(String emailAddress)
	{
		lockForRead();
		try
		{		
			if (logger.isDebugEnabled())
				logger.debug("Attempting to find user with email: " + emailAddress);
			
			return userDAO.findByEmailAddress(emailAddress);
		} 
		finally { unlockAfterRead(); }		
	}
	
	@Override
	public void createUser(BaseUser user) throws EntryAlreadyExistsException
	{
		lockForWrite();
		try
		{
			if (logger.isDebugEnabled())
				logger.debug("Attempting to create user '" + user.getUserId() + "'."); 
			
			boolean idInUse = isUserIdInUse(user.getUserId());
			if (idInUse)
			{
				logger.warn("Request to create user with an id that is already in use '" + 
								user.getUserId()+"'.");
				throw new EntryAlreadyExistsException("The userId '" + user.getUserId() + 
									"' is already in use. Cannot re-create user!");
			}
			else userDAO.save(user);
		} 
		finally { unlockAfterWrite(); }
	}

	@Override
	public void deleteUser(BaseUser user)
	{
		lockForWrite();
		try {
			if (logger.isDebugEnabled())
				logger.debug("Deleting user '" + user.getUserId() + "' ...");
			userDAO.delete(user);
		} 
		finally { unlockAfterWrite(); }		
	}

	@Override
	public boolean isUserIdInUse(String userId)
	{
		boolean result = false;
		lockForRead();
		try
		{
			if (logger.isDebugEnabled())
				logger.debug("Testing if userId '" + userId + "' is currently in use!");
			
			BaseUser user = userDAO.findByUserId(userId);			
			if (user!=null) result = true;			
		} 
		finally { unlockAfterRead(); }

		if (logger.isDebugEnabled())
			logger.debug("Is userId '" + userId + "' currently in use? " + result);

		
		return result;
	}

	@Override
	public BaseUser updateUser(BaseUser user) throws EntryNotFoundException
	{
		lockForWrite();
		try
		{
			if (isUserIdInUse(user.getUserId()))
			{
				userDAO.save(user);
				return user;
			}
			else throw new EntryNotFoundException("Could not find user with id '" + 
							user.getUserId() + "' in the system. Please verify the request and retry!");
		} 
		finally { unlockAfterWrite(); }
	}

}